#pragma once
#include <iostream>
#include <memory>
#include <functional>

namespace cr_shared
{
    template <class T>
    struct defaultdel
    {
        void operator()(T *ptr)
        {
            delete ptr;
            ptr = nullptr;
        }
    };

    template <class T, class Del = defaultdel<T>>
    class shared_ptr
    {
    private:
        T *ptr;
        int *pcount; // 共用一个
        Del del;

    public:
        shared_ptr(T *p = nullptr)
            : ptr(p)
        {
            std::cout << "shared_ptr(T *p)" << std::endl;
            pcount = new int(1);
        }

        shared_ptr(shared_ptr &p)
            : ptr(p.ptr)
        {
            std::cout << "shared_ptr(shared_ptr &p)" << std::endl;
            pcount = p.pcount;
            (*pcount)++;
        }
        shared_ptr(shared_ptr &&p)
        {
            std::cout << "std::shared_ptr(shared_ptr &&p)" << std::endl;
            ptr = p.ptr; // 内置类型
            pcount = p.pcount;
            p.ptr = nullptr;
            p.pcount = nullptr;
        }

        void release()
        {
            if (--(*pcount) == 0)
            {
                std::cout<<"void release()"<<endl;
                del(ptr);
                delete pcount;
                ptr = nullptr;
                pcount = nullptr;
            }
        }

        shared_ptr &operator=(shared_ptr &p)
        {
            if (ptr != p.ptr) // 防止自己给自己赋值
            {
                std::cout << "shared_ptr &operator=(shared_ptr &p)" << std::endl;
                release();
                ptr = p.ptr;
                pcount = p.pcount;
                (*pcount)++;
            }

            return *this;
        }
        shared_ptr &operator=(shared_ptr &&p)
        {
            if (ptr != p.ptr)
            {
                std::cout << "shared_ptr &operator=(shared_ptr &&p)" << std::endl;
                release();
                ptr = p.ptr;
                pcount = p.pcount;
                p.ptr = nullptr;
                p.pcount = nullptr;
            }
            return *this;
        }
        T *operator->()
        {
            return ptr;
        }
        T &operator*()
        {
            return *ptr;
        }
        ~shared_ptr()
        {
            release();
        }
    };
}